﻿//Szu
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Global;


namespace CharacterLibrary
{
  static public class CreatureType
    {
    //jak już walimy po bitach, szesnastkowy zapis lepiej się sprawdza
        public static int smallBall = 0x02;
        public static int bigBall   = 0x04;
        public static int pacman    = 0x08;
        public static int ghost     = 0x10; //16
        
        ///<summary>
        ///zwraca true jeśli testowana wartość jest wybranego typu
        ///(and logiczny)
        ///</summary>
        public static bool isType(int testValue, int creatureType)
        {
            if ( (testValue & creatureType) == creatureType )
                return true;
            else
                return false;
        }

    }
    public class Creatures
    {
        Random random = new Random();

        bool[,] reservedPlace;        //UWAGA: Pacman jest niewidzialny na tej tablicy
        int rows, cols;

        public Keys up { get; set; }
        public Keys down { get; set; } 
        public Keys left { get; set; } 
        public Keys right { get; set; } 

        private List<Ball> balls = new List<Ball>();
        private List<Ghost> ghosts = new List<Ghost>();
        private Pacman pacman;

        public void loadKeys()
        {
            up    = GameSettings.PacmanControl.up;
            down  = GameSettings.PacmanControl.down;
            left  = GameSettings.PacmanControl.left;
            right = GameSettings.PacmanControl.right;
        }
        private void resetPosition()
        {
            pacman.resetPosition();
            foreach (Ghost gg in ghosts)
                gg.resetPosition();
        }
        public Creatures(ContentManager content, GraphicsDeviceManager graphics, int cols, int rows, int[,] table)
        {
            KeyboardState keys = Keyboard.GetState();
            int x, y;
            this.cols = cols;
            this.rows = rows;
            //resetKeys();
            loadKeys();
            
            //Wypełnianie tablicy reservedPlace:
            reservedPlace = new bool[rows, cols];
            for (y = 0; y < cols; y++)
                for (x = 0; x < rows; x++)
                    if ( ( table[x, y] % 2 == 0 ) )          //Czy ściana
                        reservedPlace[y, x] = false;
                    else
                        reservedPlace[y, x] = true;

            //Tworzenie obiektów:
            bool pacmanExist = false;
            for (y = 0; y < cols; y++)
            {
                for (x = 0; x < rows; x++)
                {
                    if( CreatureType.isType(table[y, x], CreatureType.smallBall) )
                    {
                        balls.Add(new Ball(content, graphics, GameSettings.pointType, x, y, GameSettings.smallBallSize, Ball.BallSize.Small));     
                    }
                    else if( CreatureType.isType(table[y, x], CreatureType.bigBall) )    
                    {
                        balls.Add(new Ball(content, graphics, PointType.Ball, x, y, GameSettings.bigBallSize, Ball.BallSize.Big));
                    }
                    else if( CreatureType.isType(table[y, x], CreatureType.pacman) )    
                    {
                        if (!pacmanExist)
                        {
                            pacman = new Pacman(GameSettings.pacmanLives, content, graphics, x, y, GameSettings.pacmanSpeed);
                            pacmanExist = true;
                        }
                        else             //Jeżeli istnieje więcej niż jeden Pacman:
                        {
                            balls.Add(new Ball(content, graphics, GameSettings.pointType, x, y, GameSettings.smallBallSize, Ball.BallSize.Small ));
                        }
                    }
                    else if( CreatureType.isType(table[y, x], CreatureType.ghost) )    
                    {
                        if (GameSettings.isRandomGhostSpeed)
                            ghosts.Add(new Ghost(content, graphics, x, y, random, GameSettings.minRandomGhostSpeed, GameSettings.maxRandomGhostSpeed));
                        else
                            ghosts.Add(new Ghost(content, graphics, x, y, GameSettings.ghostSpeed));

                    }
                }
            }
        }

        public bool Update(GameTime gameTime, KeyboardState keys)
        {
                pacman.isIndestructible(gameTime);
                int index = -1; // index potworka z którym nastąpiła kolizja, -1 -> brak kolizji, ma zastosowanie przy zjadaniu potworka przez pacmana
                foreach (Ghost g in ghosts)
                {                    
                    if (pacman.IsCollison(g))
                    {
                        if (!pacman.isIndestructible(gameTime))
                        {
                            Sound.death.Play();
                            if (!pacman.living())
                            {
                                Score.elapsedLives = 0;
                                Score.points = pacman.Points;
                                return false;
                            }
                            else
                            {
                                Score.elapsedLives = pacman.Lives;
                                this.resetPosition();
                                break;
                            }
                        }
                        else // pacman połyka potworka
                        {
                            Sound.eatGhost.Play();
                            index = ghosts.IndexOf(g); // index zjedzonego duszka
                            pacman.Points += GameSettings.pointsPerGhostEaten;
                            Score.points = pacman.Points;
                        }
                    }
                    
                }
            // jeśli pacman połknął potworka to go usuwamy z listy
            // musi być poza foreach bo inaczej jest wyjątek
            if(index >= 0)
                ghosts.RemoveAt(index);
            

            for (int ii = 0; ii < balls.Count; ii++)
            {
                if (pacman.IsCollison(balls[ii]))
                {
                    pacman.ballCollision(balls[ii], gameTime);
                    balls.RemoveAt(ii--);
                    Score.points = pacman.Points;
                    Score.pointsSummary = Score.pointsAtLevelStart + Score.points;
                    if (balls.Count == 0)       //Przejście do kolejnego poziomu
                    {   
                        return false;
                    }
                }
             }


            //TODO: multiplekeys at once maybe?
            //poruszanie pacmana jest sztywne - największy
            //problem jest przy skrecaniu, a nie ma jak bo
            //się nie stoi idealnie. Warto by coś z tym zrobić. Kiedyś.
            if (keys.IsKeyDown(down))
                pacman.Direction = Pacman.DirectionType.down;
            else if (keys.IsKeyDown(up))
                pacman.Direction = Pacman.DirectionType.up;
            else if (keys.IsKeyDown(left))
                pacman.Direction = Pacman.DirectionType.left;
            else if (keys.IsKeyDown(right))
                pacman.Direction = Pacman.DirectionType.right;
            

            pacman.checkMove(rows, cols, reservedPlace);
            foreach (Ghost g in ghosts)
            {
                g.setDirection(random, rows, cols, reservedPlace );
            }
            return true;
        }

        public void Draw()
        {
            if (pacman != null)
                pacman.Move();
            foreach (Ball b in balls)
            {
                b.Draw();
            }
            foreach (Ghost g in ghosts)
            {
                if (g.canMove)
                    g.Move();
                g.Draw();
            }
            if (pacman != null)
                pacman.Draw();
        }

        
    }
}
